#pragma once

#include "atom.h"

using arma::ivec4;

class Atom::reference
{
public:
	Atom* atom;
	size_t index;
	ivec4 offset;

	reference();
	reference(Atom* const &a, const ivec4 &off = ivec4(arma::fill::zeros), size_t i = 0);

	typedef std::vector<reference> list;
	
	long i() const;
	long j() const;
	long h() const;
	long l() const;

	ivec4 ijhl() const;
	
	double x() const;
	double y() const;
	double z() const;
	
	vec3 xyz() const;
	vec2 xy() const;

	class grid;
};

using arma::imat;
using arma::vec2;

// This class is used to divide an Atom::list into cells, effectively reducing the amount of surrounding atoms per atom.
class Atom::reference::grid
{
public:
  static const double dx,dy;	// These define the grid-cell dimensions.
  
private:
  Atom::list* atoms;	// This references the list, onto which this grid has been calculated.
  imat* offsets;
  
  arma::field<reference::list> grid2d;	// This contains the cells of the grid.
  
  vec2 origin; // This contains the origin in (x,y) space of the first cell (lower left corner).
  
public:
  grid();	// The default constructor, use setAtoms() to set the list onto which this grid should be calculated.
  grid(Atom::list* const &list, imat* const &offs = nullptr); // Overload constructor, this set the list, and if the list is not empty generates the grid.
  
  void setAtoms(Atom::list* const &list, imat* const &offs = nullptr); // This set the list, and if the list is not empty generates the grid.

  void operator()(); // If the Atom::list reference is set this re-generates the grid.
  
  const reference::list &getSurrounding(const Atom &a, long di, long dj); // This returns a subview of the cells surrounding the atom a.

  void clear();
};